#ifndef CHARACTERSET_H
#define CHARACTERSET_H

#ifdef SCI_NAMESPACE
namespace Scintilla {
#endif

  class CharacterSet {
      int size;
      bool valueAfter;
      bool *bset;
    public:
      enum setBase {
        setNone = 0,
        setLower = 1,
        setUpper = 2,
        setDigits = 4,
        setAlpha = setLower | setUpper,
        setAlphaNum = setAlpha | setDigits
      };
      CharacterSet( setBase base = setNone, const char *initialSet = "", int size_ = 0x80, bool valueAfter_ = false ) {
        size = size_;
        valueAfter = valueAfter_;
        bset = new bool[size];
        for( int i = 0; i < size; i++ ) {
          bset[i] = false;
        }
        AddString( initialSet );
        if( base & setLower ) {
          AddString( "abcdefghijklmnopqrstuvwxyz" );
        }
        if( base & setUpper ) {
          AddString( "ABCDEFGHIJKLMNOPQRSTUVWXYZ" );
        }
        if( base & setDigits ) {
          AddString( "0123456789" );
        }
      }
      CharacterSet( const CharacterSet &other ) {
        size = other.size;
        valueAfter = other.valueAfter;
        bset = new bool[size];
        for( int i = 0; i < size; i++ ) {
          bset[i] = other.bset[i];
        }
      }
      ~CharacterSet() {
        delete []bset;
        bset = 0;
        size = 0;
      }
      CharacterSet &operator=( const CharacterSet &other ) {
        if( this != &other ) {
          bool *bsetNew = new bool[other.size];
          for( int i = 0; i < other.size; i++ ) {
            bsetNew[i] = other.bset[i];
          }
          delete []bset;
          size = other.size;
          valueAfter = other.valueAfter;
          bset = bsetNew;
        }
        return *this;
      }
      void Add( int val ) {
        assert( val >= 0 );
        assert( val < size );
        bset[val] = true;
      }
      void AddString( const char *setToAdd ) {
        for( const char *cp = setToAdd; *cp; cp++ ) {
          int val = static_cast<unsigned char>( *cp );
          assert( val >= 0 );
          assert( val < size );
          bset[val] = true;
        }
      }
      bool Contains( int val ) const {
        assert( val >= 0 );
        if( val < 0 ) {
          return false;
        }
        return ( val < size ) ? bset[val] : valueAfter;
      }
  };


  inline bool IsASpace( int ch ) {
    return ( ch == ' ' ) || ( ( ch >= 0x09 ) && ( ch <= 0x0d ) );
  }

  inline bool IsASpaceOrTab( int ch ) {
    return ( ch == ' ' ) || ( ch == '\t' );
  }

  inline bool IsADigit( int ch ) {
    return ( ch >= '0' ) && ( ch <= '9' );
  }

  inline bool IsADigit( int ch, int base ) {
    if( base <= 10 ) {
      return ( ch >= '0' ) && ( ch < '0' + base );
    } else {
      return ( ( ch >= '0' ) && ( ch <= '9' ) ) ||
             ( ( ch >= 'A' ) && ( ch < 'A' + base - 10 ) ) ||
             ( ( ch >= 'a' ) && ( ch < 'a' + base - 10 ) );
    }
  }

  inline bool IsASCII( int ch ) {
    return ( ch >= 0 ) && ( ch < 0x80 );
  }

  inline bool IsLowerCase( int ch ) {
    return ( ch >= 'a' ) && ( ch <= 'z' );
  }

  inline bool IsUpperCase( int ch ) {
    return ( ch >= 'A' ) && ( ch <= 'Z' );
  }

  inline bool IsAlphaNumeric( int ch ) {
    return
      ( ( ch >= '0' ) && ( ch <= '9' ) ) ||
      ( ( ch >= 'a' ) && ( ch <= 'z' ) ) ||
      ( ( ch >= 'A' ) && ( ch <= 'Z' ) );
  }


  inline bool isspacechar( int ch ) {
    return ( ch == ' ' ) || ( ( ch >= 0x09 ) && ( ch <= 0x0d ) );
  }

  inline bool iswordchar( int ch ) {
    return IsAlphaNumeric( ch ) || ch == '.' || ch == '_';
  }

  inline bool iswordstart( int ch ) {
    return IsAlphaNumeric( ch ) || ch == '_';
  }

  inline bool isoperator( int ch ) {
    if( IsAlphaNumeric( ch ) ) {
      return false;
    }
    if( ch == '%' || ch == '^' || ch == '&' || ch == '*' ||
        ch == '(' || ch == ')' || ch == '-' || ch == '+' ||
        ch == '=' || ch == '|' || ch == '{' || ch == '}' ||
        ch == '[' || ch == ']' || ch == ':' || ch == ';' ||
        ch == '<' || ch == '>' || ch == ',' || ch == '/' ||
        ch == '?' || ch == '!' || ch == '.' || ch == '~' ) {
      return true;
    }
    return false;
  }


  inline char MakeUpperCase( char ch ) {
    if( ch < 'a' || ch > 'z' ) {
      return ch;
    } else
    { return static_cast<char>( ch - 'a' + 'A' ); }
  }

  int CompareCaseInsensitive( const char *a, const char *b );
  int CompareNCaseInsensitive( const char *a, const char *b, size_t len );

  #ifdef SCI_NAMESPACE
}
  #endif

#endif
